package com.pig4cloud.pig.auth.support.handler;

import cn.hutool.core.util.StrUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpHeaders;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import java.io.IOException;

/**
 * SSO 登出成功处理器
 * <p>
 * 该类实现了 Spring Security 的 LogoutSuccessHandler 接口，
 * 用于处理单点登出（SSO Logout）成功后的重定向逻辑。
 * 
 * 主要功能：
 * 1. 支持根据客户端传入的 redirect_url 参数进行重定向
 * 2. 如果没有指定 redirect_url，则重定向到 Referer 页面
 * 3. 为 SSO 场景提供灵活的登出后跳转策略
 * 
 * 使用场景：
 * - 多个应用集成 SSO 时的统一登出
 * - 用户从子系统登出后需要返回原系统
 *
 * @author lengleng
 * @date 2025/05/30
 */
public class SsoLogoutSuccessHandler implements LogoutSuccessHandler {

	/**
	 * 重定向 URL 参数名称
	 * 客户端可以通过这个参数指定登出后的跳转地址
	 */
	private static final String REDIRECT_URL = "redirect_url";

	/**
	 * 登出成功处理逻辑
	 * <p>
	 * 处理流程：
	 * 1. 首先检查响应对象是否有效
	 * 2. 优先使用请求参数中的 redirect_url 进行重定向
	 * 3. 如果没有 redirect_url，则使用 HTTP Referer 头进行重定向
	 * 4. 如果都没有，则不进行重定向操作
	 * 
	 * 安全注意事项：
	 * - 在生产环境中应该验证 redirect_url 的合法性，避免开放重定向漏洞
	 * - 建议维护一个白名单列表，只允许重定向到可信任的域名
	 * 
	 * @param request HTTP请求
	 * @param response HTTP响应
	 * @param authentication 认证信息（可能为 null）
	 * @throws IOException 重定向失败时抛出 IO 异常
	 */
	@Override
	public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
			throws IOException {
		// 防御性编程：检查响应对象是否有效
		if (response == null) {
			return;
		}

		// 优先级 1：获取请求参数中的重定向地址
		// 允许客户端通过 ?redirect_url=xxx 参数指定登出后的跳转地址
		String redirectUrl = request.getParameter(REDIRECT_URL);
		if (StrUtil.isNotBlank(redirectUrl)) {
			// TODO: 生产环境应添加 URL 白名单验证，避免开放重定向漏洞
			response.sendRedirect(redirectUrl);
		}
		// 优先级 2：使用 HTTP Referer 头
		// 当用户从某个页面发起登出请求时，返回到原页面
		else if (StrUtil.isNotBlank(request.getHeader(HttpHeaders.REFERER))) {
			String referer = request.getHeader(HttpHeaders.REFERER);
			response.sendRedirect(referer);
		}
		// 如果以上两种情况都不满足，则不进行重定向
		// 浏览器将停留在当前页面或显示空白页
	}

}
